#include "manipulatormanager.h"
#include "mainmanipulator.h"
#include "createdevicemanipulator.h"
#include "simpleeditmovemanipulator.h"
#include "viewer.h"
#include "scene.h"
#include "qsignalslotcenter.h"
#include "roammanipulator.h"
#include "hotpointmanipulator.h"
#include "terrainbrushmanipulator.h"
#include "attachobjectmanipulator.h"
#include "insertmanipulator.h"
#include "planemanipulator.h"
#include "cameraanimationmanipulator.h"

namespace ControlCenter
{
	ManipulatorManager::ManipulatorManager(CoreBase::Viewer* viewer,CoreBase::Scene* scene
		,int viewtype):_preManipulator(NULL)
		,_currentManipulator(NULL),_viewType(viewtype)
	{
		_viewer = viewer;
		_scene = scene;
		QObject::connect(&QSignalSlotCenter::QSignalSlotCenter::GetInstance(),SIGNAL(signalManipulatorModeChange(const QString&))
			,this,SLOT(slotManipulatorModeChange(const QString&)));
		QObject::connect(&QSignalSlotCenter::QSignalSlotCenter::GetInstance(),SIGNAL(signalManipulatorModeChangeWithObjs(
			const QString&,QVector<CoreBase::ActorBase*>,bool))
			,this,SLOT(slotManipulatorModeChangeWithObjs(const QString&,QVector<CoreBase::ActorBase*>,bool)));
		QObject::connect(&QSignalSlotCenter::QSignalSlotCenter::GetInstance(),SIGNAL(signalActionTrigger(int))
			,this,SLOT(setAction(int)));
	}

	ManipulatorManager::~ManipulatorManager()
	{}

	void ManipulatorManager::setOperateObjectType(int type)
	{
		QMap<QString,osg::ref_ptr<ManipulatorBase>>::Iterator iter = _registerManipulators.begin();
		for(;iter!=_registerManipulators.end();++iter)
		{
			iter.value()->setOperateObjectType(type);
		}
	}

	void ManipulatorManager::resetManager()
	{
		switch (_viewType)
		{
		case VIEW_TYPE_EDITER:
			registerManipulator(CLASS_MANIPULATOR_MAIN);
			registerManipulator(CLASS_MANIPULATOR_CREATEDEVICE);
			registerManipulator(CLASS_MANIPULATOR_HOTPOINT);
			registerManipulator(CLASS_MANIPULATOR_SIMPLEEDITMOVE);
			registerManipulator(CLASS_MANIPULATOR_TERRAINBRUSH);
			registerManipulator(CLASS_MANIPULATOR_INSERT);
			registerManipulator(CLASS_MANIPULATOR_PLANE);
			registerManipulator(CLASS_MANIPULATOR_CAMERAANIMATION);
			registerManipulator(CLASS_MANIPULATOR_ROAM);
			registerManipulator(CLASS_MANIPULATOR_SINGLEOBJECT);
			enableCollisionCamera(CLASS_MANIPULATOR_ROAM,true);
			slotManipulatorModeChange(CLASS_MANIPULATOR_MAIN);
			break;
		case VIEW_TYPE_SHOW:
			registerManipulator(CLASS_MANIPULATOR_ROAM);
			registerManipulator(CLASS_MANIPULATOR_CONST_HEIGHT_ROAM);
			registerManipulator(CLASS_MANIPULATOR_ATTACHOBJECT);
			//slotManipulatorModeChange(CLASS_MANIPULATOR_ROAM);
			enableCollisionCamera(CLASS_MANIPULATOR_ROAM,true);
			registerManipulator(CLASS_MANIPULATOR_MAIN);
			registerManipulator(CLASS_MANIPULATOR_INSERT);
			registerManipulator(CLASS_MANIPULATOR_CAMERAANIMATION);
			enableCollisionCamera(CLASS_MANIPULATOR_CONST_HEIGHT_ROAM,true);
			slotManipulatorModeChange(CLASS_MANIPULATOR_MAIN);
			break;
		default:
			break;
		}
	}

	void ManipulatorManager::registerManipulator(const QString& mode)
	{
		if(!_registerManipulators.contains(mode))
		{
			osg::ref_ptr<ManipulatorBase> mpl = NULL;
			if(mode == CLASS_MANIPULATOR_MAIN)
			{
				mpl = new MainManipulator;
				_registerManipulators.insert(CLASS_MANIPULATOR_MAIN,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_SINGLEOBJECT)
			{
				mpl = new MainManipulator;
				_registerManipulators.insert(CLASS_MANIPULATOR_MAIN,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_CREATEDEVICE)
			{
				mpl = new CreateDeviceManipulator(_viewer->getCamera());
				_registerManipulators.insert(CLASS_MANIPULATOR_CREATEDEVICE,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_SIMPLEEDITMOVE)
			{
				mpl = new SimpleEditMoveManipulator(_viewer->getCamera());
				_registerManipulators.insert(CLASS_MANIPULATOR_SIMPLEEDITMOVE,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_ROAM)
			{
				mpl = new RoamManipulator();
				_registerManipulators.insert(CLASS_MANIPULATOR_ROAM,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_CONST_HEIGHT_ROAM)
			{
				mpl = new RoamManipulator();
				dynamic_cast<RoamManipulator*>(mpl.get())->setConstHeight(1000);
				_registerManipulators.insert(CLASS_MANIPULATOR_CONST_HEIGHT_ROAM,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_HOTPOINT)
			{
				mpl = new HotPointManipulator();
				_registerManipulators.insert(CLASS_MANIPULATOR_HOTPOINT,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_ATTACHOBJECT)
			{
				mpl = new AttachObjectManipulator();
				_registerManipulators.insert(CLASS_MANIPULATOR_ATTACHOBJECT,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_TERRAINBRUSH)
			{
				mpl = new TerrainBrushManipulator(_viewer->getCamera());
				_registerManipulators.insert(CLASS_MANIPULATOR_TERRAINBRUSH,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_INSERT)
			{
				mpl = new InsertManipulator(_viewer->getCamera());
				_registerManipulators.insert(CLASS_MANIPULATOR_INSERT,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_PLANE)
			{
				mpl = new PlaneManipulator(_viewer->getCamera());
				_registerManipulators.insert(CLASS_MANIPULATOR_PLANE,mpl);
			}
			else if(mode == CLASS_MANIPULATOR_CAMERAANIMATION)
			{
				mpl = new CameraAnimationManipulator(_viewer);
				_registerManipulators.insert(CLASS_MANIPULATOR_CAMERAANIMATION,mpl);
			}
			else
				return;
			mpl->setViewType(_viewType);
		}
	}

	void ManipulatorManager::setSpeed(float speed)
	{
		_currentManipulator->setSpeed(speed);
	}

	void ManipulatorManager::setAction(ActionData* action)
	{
		_currentManipulator->setToolAction(action);
	}

	void ManipulatorManager::setAction(int actionkey)
	{
		ActionData newdata;
		newdata._actionKey = actionkey;
		newdata._userDefineData = NULL;
		_currentManipulator->setToolAction(&newdata);
	}

	ManipulatorBase* ManipulatorManager::getManipulatorByMode(const QString& mode)
	{
		QString curmode = mode == ""?_currentManipulatorMode:mode;
		if(_registerManipulators.contains(curmode))
			return _registerManipulators.value(curmode).get();
		return NULL;
	}

	QString ManipulatorManager::getCurrentManipulatorMode()
	{
		return _currentManipulatorMode;
	}

	void ManipulatorManager::initManipulatorStart(const QString& mode,const osg::Vec3& eye,const osg::Vec3& center,const osg::Vec3& up)
	{
		ManipulatorBase* mpl = getManipulatorByMode(mode);
		mpl->initManipulatorStart(eye,center,up);
	}

	void ManipulatorManager::clearAllRegisterManipulators()
	{
		_viewer->setCameraManipulator(NULL);
		_preManipulator = NULL;
		_currentManipulator = NULL;
		_currentManipulatorMode = "";
		_registerManipulators.clear();
	}

	void ManipulatorManager::unregisterManipulator(const QString& mode)
	{
		if(_currentManipulatorMode!= mode && _registerManipulators.contains(mode))
		{
			_registerManipulators.remove(mode);
		}
	}

	void ManipulatorManager::addChange(ManipulatorBase* mapl,QVector<CoreBase::ActorBase*> vector,bool setdefaultstart)
	{
		_preManipulator = _currentManipulator;
		_currentManipulator = mapl;
		osg::Vec3 preeye,cureye;
		osg::Vec3 precenter,curcenter;
		osg::Vec3 preup,curup;
		float predistance = 1.0f,curdistance = 1.0f;
		if(_preManipulator!=NULL && _currentManipulator!=NULL)
		{
			_preManipulator->getLookAt(preeye,precenter,preup,predistance);
			_currentManipulator->getLookAt(cureye,curcenter,curup,curdistance);
			_currentManipulator->setLookAt(preeye,precenter,preup,predistance,false);
			if(setdefaultstart)
			{
				_currentManipulator->setLookAt(cureye,curcenter,curup,curdistance,true);
			}
		}
		setOperatorObjectVector(vector);
		if(_preManipulator!=NULL)
			_preManipulator->disenableManipulator();
		_currentManipulator->enableManipulator();
	}

	void ManipulatorManager::slotManipulatorModeChange(const QString& mode,bool setdefaultstart)
	{
		if(mode == CLASS_PRE_MANIPULATOR)
		{
			_currentManipulatorMode = _registerManipulators.key(_preManipulator);
			addChange(_preManipulator,_operatorObjectVector,setdefaultstart);
			_currentManipulator->flushKeyEventStack();
			_currentManipulator->flushMouseEventStack();
			_viewer->setCameraManipulator(_currentManipulator);
		}
		else if(mode != _currentManipulatorMode && _registerManipulators.contains(mode))
		{
			_currentManipulatorMode = mode;
			ManipulatorBase* newmapl = _registerManipulators.value(mode).get();
			addChange(newmapl,_operatorObjectVector,setdefaultstart);
			_currentManipulator->flushKeyEventStack();
			_currentManipulator->flushMouseEventStack();
			_viewer->setCameraManipulator(_currentManipulator);
		}
	}

	void ManipulatorManager::slotManipulatorModeChangeWithObjs(const QString& mode,QVector<CoreBase::ActorBase*> vector,bool setdefaultstart)
	{
		if(mode != _currentManipulatorMode && _registerManipulators.contains(mode))
		{
			_currentManipulatorMode = mode;
			ManipulatorBase* newmapl = _registerManipulators.value(mode).get();
			addChange(newmapl,vector,setdefaultstart);
			_currentManipulator->flushKeyEventStack();
			_currentManipulator->flushMouseEventStack();
			_viewer->setCameraManipulator(_currentManipulator);
		}
	}

	void ManipulatorManager::setViewer(CoreBase::Viewer* viewer)
	{
		_viewer = viewer;
	}

	void ManipulatorManager::setScene(CoreBase::Scene* scene)
	{
		_scene = scene;
	}

	void ManipulatorManager::setOperatorObjectVector(QVector<CoreBase::ActorBase*> objvector)
	{
		_operatorObjectVector = objvector;
		_currentManipulator->setOperatorObjectVector(objvector);
	}

	void ManipulatorManager::addOperatorObject(CoreBase::ActorBase* obj)
	{
		_operatorObjectVector.push_back(obj);
		_currentManipulator->setOperatorObjectVector(_operatorObjectVector);
	}

	QVector<CoreBase::ActorBase*> ManipulatorManager::getOperatorObjectVector()
	{
		return _operatorObjectVector;
	}

	void ManipulatorManager::setLookAt(const osg::Vec3& meye,const osg::Vec3& mcenter,const osg::Vec3& mup,float distance)
	{
		_currentManipulator->setLookAt(meye,mcenter,mup,distance,true);
	}

	void ManipulatorManager::getLookAt(float& eyex,float& eyey,float& eyez,float& centerx,float& centery,
											float& centerz,float& upx,float& upy,float& upz,float& distance)
	{
		osg::Vec3 eye,center,up;
		float dis = 0;
		_currentManipulator->getLookAt(eye,center,up,dis);
		eyex = eye.x();
		eyey = eye.y();
		eyez = eye.z();
		centerx = center.x();
		centery = center.y();
		centerz = center.z();
		upx = up.x();
		upy = up.y();
		upz = up.z();
		distance = dis;
	}

	void ManipulatorManager::enableCollisionCamera(const QString& mode,bool enable)
	{
		QMap<QString,osg::ref_ptr<ManipulatorBase>>::Iterator iter = _registerManipulators.find(mode);
		if(iter!=_registerManipulators.end())
		{
			if(enable)
				_registerManipulators.value(mode)->useCollisionCamera(true);
			else
				_registerManipulators.value(mode)->useCollisionCamera(false);
		}
	}

	void ManipulatorManager::openCameraInSky(bool open)
	{
		QMap<QString,osg::ref_ptr<ManipulatorBase>>::Iterator iter = _registerManipulators.begin();
		for(;iter!=_registerManipulators.end();++iter)
		{
			iter.value()->openCameraInSky(open);
		}
	}
}